#pragma once
#include <iostream>
#include <queue>
namespace ns_pthreadpool
{
    const int g_num = 5;
    template<class T>
    class ThreadPool
    {
    public:
        ThreadPool(int num = g_num)
            :_num(num) 
        {
            pthread_mutex_init(&_mtx,nullptr);
            pthread_cond_init(&_cond,nullptr);
        }
        static void* Rountine(void* args)
        {
            pthread_detach(pthread_self());
            ThreadPool<T>* tp = (ThreadPool<T>*)args;
            while(true)
            {
                tp->Lock();
                while(tp->empty())
                {
                    tp->Wait();
                }
                T t;
                tp->PopTask(&t);
                tp->Unlock();

                t();//处理任务
            }
        }
        void InitThreadPool()
        {
            pthread_t tid;
            for(int i=0;i<_num;i++)
            {
                pthread_create(&tid,nullptr,Rountine,(void*)this);
            }
        }
        ~ThreadPool() 
        {
            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_cond);
        }
        void PushTask(T& in)
        {
            Lock();
            _task_queue.push(in);
            Unlock();
            Wakeup();
        }
        void PopTask(T* out)//在上锁区内调用，里面不用再上锁
        {
            *out = _task_queue.front();
            _task_queue.pop();
        }
    private:
        void Lock()
        {
            pthread_mutex_lock(&_mtx);
        }
        void Unlock()
        {
            pthread_mutex_unlock(&_mtx);
        }
        void Wait()
        {
            pthread_cond_wait(&_cond,nullptr);
        }
        void Wakeup()
        {
            pthread_cond_signal(&_cond);
        }
        bool empty()
        {
            return _task_queue.empty();
        }
        int _num;
        std::queue<T> _task_queue;
        pthread_mutex_t _mtx;
        pthread_cond_t _cond;
    };
} // namespace ns_pthread_pool
